import path from 'path';

import { expect } from '@jest/globals';
import * as compressing from 'compressing';
import fse from 'fs-extra';

import { runHvigorAsync } from '../../common/common';
import {
  AbilityType,
  APIType,
  APIVersion,
  CaseLevel,
  LanguageType,
  ModuleTemplateType,
  RuntimeOSType,
  SDKType
} from '../../plugins/project-builder/models/constants';
import { TestCaseBuilder } from '../../plugins/task-builder/task-case-builder';
import { ProjectBuildOption, TestCaseFun } from '../../plugins/task-builder/test-case';
import { TestTaskOptionBuilder } from '../../plugins/task-builder/test-task-option';

const projectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.STAGE,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.NativeC
  }
};

const testfun: TestCaseFun = async (project, taskConfig, record) => {
  // 1. 创建API10 stage native工程
  const entryPath = project.getModule('entry').moduleRootPath();
  const resfilePath = path.resolve(entryPath, 'src/main/resources/resfile');
  const rawfilePath = path.resolve(entryPath, 'src/main/resources/rawfile');
  const ajsonPath = path.resolve(resfilePath, 'a.json');
  const ajsonPath2 = path.resolve(rawfilePath, 'a.json');
  fse.ensureDirSync(resfilePath);
  fse.ensureDirSync(rawfilePath);
  fse.writeJSONSync(ajsonPath, { a: 'a' });
  fse.writeJSONSync(ajsonPath2, { a: 'a' });

  // 2. sync一下，避免执行clean
  const syncCommand = '--sync -p product=default --analyze=normal --parallel --incremental --no-daemon'.split(' ');
  const syncResult = await runHvigorAsync(project.projectRootPath(), syncCommand);
  record.addStep('sync', syncResult);

  // 3. 创建entry\build\config\buildConfig.json文件
  const buildConfig = createBuildConfig(entryPath);
  const buildConfigDir = path.resolve(entryPath, 'build', 'config');
  fse.ensureDirSync(buildConfigDir);
  fse.writeJSONSync(path.resolve(buildConfigDir, 'buildConfig.json'), buildConfig);
  expect(fse.existsSync(path.resolve(buildConfigDir, 'buildConfig.json'))).toEqual(true);

  const commonCommand = [
    '--mode module -p module=entry@default -p product=default -p requiredDeviceType=phone',
    '--analyze=normal --parallel --incremental --no-daemon'
  ];

  // 4. 第一次全量构建
  const buildCommand: string[] = [commonCommand[0], 'assembleHap', commonCommand[1]].join(' ').split(' ');
  const buildResult = await runHvigorAsync(project.projectRootPath(), buildCommand);
  record.addStep('冷重载第一次构建hap', buildResult);
  expect(buildResult.stdout).toContain('BUILD SUCCESSFUL');

  // 5. 修改cpp文件
  const napiInitCppPath = path.resolve(entryPath,'src/main/cpp/hello.cpp');
  const napiInitCppContent = fse.readFileSync(napiInitCppPath).toString();
  const ModifyNapiInitCppContent = napiInitCppContent.replace('size_t argc = 2;','size_t argc = 2;\r\nsize_t argc2 = 2;');
  fse.writeFileSync(napiInitCppPath, ModifyNapiInitCppContent);

  // 5. 创建changedFileList.json
  const changedFileListPath = path.resolve(entryPath, 'build/default/intermediates/patch/default/changedFileList.json');
  fse.writeJSONSync(changedFileListPath, createChangedFileList(ajsonPath, ajsonPath2));

  // 6. 构建生成hqf
  const coldReloadCommand: string[] = [commonCommand[0], 'assembleDevHqf', commonCommand[1]].join(' ').split(' ');
  const coldReloadResult = await runHvigorAsync(project.projectRootPath(), coldReloadCommand);
  record.addStep('冷重载构建hqf', coldReloadResult);
  expect(coldReloadResult.stdout).toContain('BUILD SUCCESSFUL');

  // 7. 检测hqf包中是否存在资源文件和so
  const outputDir =
    await parse(path.resolve(entryPath, 'build/default/outputs/default/entry-default-unsigned.hqf'));
  expect(fse.existsSync(path.resolve(outputDir, 'patch.json'))).toEqual(true);
  expect(fse.existsSync(path.resolve(outputDir, 'libs', 'arm64-v8a', 'libentry.so'))).toEqual(true);
  expect(fse.existsSync(path.resolve(outputDir, 'resources', 'resfile', 'a.json'))).toEqual(true);
  expect(fse.existsSync(path.resolve(outputDir, 'resources', 'rawfile', 'a.json'))).toEqual(true);
};

/**
 * 返回buildConfig, 只生成patchConfig， compileConfig暂时不用
 * @param {string} modulePath
 * @returns
 */
function createBuildConfig(modulePath: string) {
  return {
    patchConfig: {
      changedFileList:
        path.resolve(modulePath, 'build/default/intermediates/patch/default/changedFileList.json'),
    }
  };
}

/**
 * 生成“修改Index.ets”对应的changedFileList
 */
function createChangedFileList(aJsonPath: string, aJsonPath2: string) {
  return {
    'resources': {
      'resFile': [
        {
          'filePath': aJsonPath,
          'resourcePath': aJsonPath.substring(0, aJsonPath.indexOf('resfile'))
        }
      ],
      'rawFile': [
        {
          'filePath': aJsonPath2,
          'resourcePath': aJsonPath2.substring(0, aJsonPath2.indexOf('rawfile'))
        }
      ]
    }
  };
}

/**
 * 解析hqf包
 * @param {string} hqfPath hqf包的绝对路径
 * @returns {Promise<string>} 解析的产物目录
 */
async function parse(hqfPath: string) {
  const dir = path.dirname(hqfPath);
  let fileName = path.basename(hqfPath);
  fileName = fileName.replace(fileName.slice(-3), 'zip');
  const zipPath = path.resolve(dir, fileName);

  // 将生成的xxx包复制为zip包
  fse.copyFileSync(hqfPath, zipPath);

  // 解压zip，解析出生成hap里的内容
  const outputDir = zipPath.slice(0, -4);
  await compressing.zip.uncompress(zipPath, outputDir);

  return outputDir;
}

TestCaseBuilder.builder()
  .caseName('COLD_RELOAD')
  .description('1. 创建API10 stage native工程；\n' +
    '2. sync一下；\n' +
    '3. 创建entry/build/config/buildConfig.json文件；\n' +
    '4. 第一次全量构建；\n' +
    '5. 修改cpp文件；\n' +
    '5. 创建changedFileList.json；\n' +
    '6. 构建生成hqf；\n' +
    '7. 检测hqf包中是否含有资源文件和so文件；\n'
  )
  .projectBuilderOption(projectBuilderOption)
  .taskConfig(TestTaskOptionBuilder.builder().caseLevel(CaseLevel.AR).build())
  .testFun(testfun)
  .load();
